/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.spi.jsonser.abstractcefchange;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.apache.commons.lang3.time.FastDateFormat;

import java.io.IOException;
import java.text.ParseException;
import java.util.Date;

public class BefDateSerUtil {

    private static BefDateSerUtil instace = new BefDateSerUtil();
    private FastDateFormat stdDateTimeFormatNoSSS = null;
    private FastDateFormat stdDateTimeFormat = null;
    private FastDateFormat dateTimeFormat = null;
    private FastDateFormat dateFormat = null;

    // region 读取
    @Deprecated
    public BefDateSerUtil() {
    }

    public static BefDateSerUtil getInstance() {
        return instace;
    }

    private FastDateFormat getStdDateTimeFormatNoSSS() {
        if (stdDateTimeFormatNoSSS == null) {
            stdDateTimeFormatNoSSS = FastDateFormat
                    .getInstance("yyyy-MM-dd'T'HH:mm:ssXXX");
        }
        return stdDateTimeFormatNoSSS;
    }

    private FastDateFormat getStdDateTimeFormat() {
        if (stdDateTimeFormat == null) {
            stdDateTimeFormat = FastDateFormat
                    .getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
        }
        return stdDateTimeFormat;
    }

    private FastDateFormat getDateTimeFormat() {
        if (dateTimeFormat == null) {
            dateTimeFormat = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
        }
        return dateTimeFormat;
    }

    private FastDateFormat getDateFormat() {
        if (dateFormat == null) {
            dateFormat = FastDateFormat.getInstance("yyyy-MM-dd");
        }
        return dateFormat;
    }

    /**
     * 反序列化日期时间值
     *
     * @param p 读取器
     */
    public final java.util.Date readDateTime(JsonParser p) {
        try {
            if (JsonToken.VALUE_NULL.equals(p.getCurrentToken())) {
                return null;
            } else {
                String strValue = p.getValueAsString();
                return readDateTime(strValue);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public final java.util.Date readDateTime(Object value) {
        if (value == null) {
            return null;
        }
        return readDateTime(value.toString());
    }

    public final java.util.Date readDateTime(JsonNode value) {
        if (value.isNull()) {
            return null;
        }
        return readDateTime(value.textValue());
    }

    /**
     * 反序列化日期时间值
     *
     * @param strValue 字符串
     */
    public final java.util.Date readDateTime(String strValue) {
        return readDateTime(strValue, this.getDateTimeFormat());
    }

    /**
     * 反序列化标准时间格式
     */
    public final java.util.Date readStdDateTime(JsonParser p) {
        try {
            if (JsonToken.VALUE_NULL.equals(p.getCurrentToken())) {
                return null;
            } else {
                String strValue = p.getValueAsString();
                return readStdDateTime(strValue);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public final Date readStdDateTime(JsonNode node) {
        if (node.isNull())
            return null;
        String strValue = node.textValue();
        return readStdDateTime(strValue);
    }

    public final java.util.Date readStdDateTime(Object value) {
        if (value == null) {
            return null;
        }
        return readStdDateTime(value.toString());
    }


    public final java.util.Date readStdDateTime(String strValue) {
        try {
            if (strValue != null && strValue.length() == 13) {
                Date date = new Date();
                date.setTime(Long.parseLong(strValue));
                return date;
            }
            if (strValue == null || strValue.equals("")) {
                return null;
            }
            // 日期
            if (!strValue.contains("T")) {
                return readDateTime(strValue, this.getDateTimeFormat());
            }
            // 兼容无毫秒2020-02-01T11:26:57+08:00
            if (!strValue.contains(".")) {
                return getStdDateTimeFormatNoSSS().parse(strValue);
            }
            return getStdDateTimeFormat().parse(strValue);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    private final java.util.Date readDateTime(String strValue, FastDateFormat format) {
        try {
            if (strValue != null && strValue.length() == 13) {
                Date date = new Date();
                date.setTime(Long.parseLong(strValue));
                return date;
            }

            if (strValue != null && !strValue.equals("")) {
                if (strValue.startsWith("\"")) {
                    strValue = strValue.substring(1, strValue.length() - 1);
                }
                if (strValue.contains("T")) {
                    strValue = strValue.replace("T", " ");
                }
                if (strValue.contains(".")) {
                    strValue = strValue.substring(0, strValue.indexOf('.'));
                }
                if (!strValue.contains(" ")) {
                    strValue = strValue.concat(" 00:00:00");
                }

                return getDateTimeFormat().parse(strValue);
            } else {
                return null;
            }
        } catch (ParseException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    // endregion

    // region 序列化

    /**
     * 序列化日期时间值
     *
     * @param date 日期时间
     */
    public final String writeDateTime(java.util.Date date) {
        return this.writeDateTimeWithFormat(date, getDateTimeFormat());
    }

    /**
     * 序列化标准格式日期时间值
     *
     * @param date 日期时间
     */
    public final String writeStdDateTime(java.util.Date date) {
        return this.writeDateTimeWithFormat(date, this.getStdDateTimeFormat());
    }

    /**
     * 序列化日期值
     *
     * @param date 日期
     */
    public final String writeDate(java.util.Date date) {
        if (date == null) {
            return "";
        }
        String json = getDateFormat().format(date);
        return json;
    }

    public <T> ObjectMapper getDeserializer(Class<T> deSerClasses,
                                            JsonDeserializer<? extends T> deser) {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        if (deser != null) {
            module.addDeserializer(deSerClasses, deser);
        }
        mapper.registerModule(module);
        return mapper;
    }

    public <T> ObjectMapper getSerializer(Class<? extends T> serClasses, JsonSerializer<T> ser) {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        if (ser != null) {
            module.addSerializer(serClasses, ser);
        }
        mapper.registerModule(module);

        return mapper;

    }

    public void writeDateTime(JsonGenerator jsonGenerator, Date value) throws IOException {
        jsonGenerator.writeString(writeDateTime(value));
    }

    private final String writeDateTimeWithFormat(java.util.Date date, FastDateFormat format) {
        if (date == null) {
            return "";
        }
        String json = format.format(date);
        return json;
    }

    // endregion
}
